<?php

namespace yunj\init\step;

use think\facade\Db;
use yunj\app\admin\service\auth\AuthService;

/**
 * 基础数据初始化
 * Class BaseDataInit
 * @package yunj\init\step
 */
class BaseDataInit extends Step {

    const TABLES = [
        'admin_auth', 'admin_member', 'admin_member_log', 'admin_member_log_attr', 'admin_member_role',
        'admin_member_role_relation', 'admin_route', 'admin_route_group', 'admin_route_request',
        'setting'
    ];

    /**
     * 是否初始化数据库
     * @var bool
     */
    private $isInit = false;

    /**
     * @var string
     */
    private $username;

    /**
     * @var string
     */
    private $password;

    public function handle() {
        $res = $this->checkBase();
        if ($res == self::RES_SKIP) return self::RES_SKIP;
        $this->initDb();
        return self::RES_SUCCESS;
    }

    // 简单基础校验
    private function checkBase() {
        $prefix = $this->getDbConnConfig('prefix');
        // 数据表是否存在
        $existCount = 0;    // 存在的表数量
        $tables = self::TABLES;
        foreach ($tables as $table) {
            $exist = Db::query("show tables like '{$prefix}{$table}'");
            if ($exist) {
                $existCount++;
            }
        }
        $allExist = count($tables) === $existCount;   // 是否都存在
        if ($existCount) {
            $tableStr = implode('、', $tables);
            if ($allExist) {
                // 全部存在
                if (!$this->confirm("是否重置系统数据表[{$tableStr}]？否 将跳过 {$this->desc} 流程")) {
                    return self::RES_SKIP;
                }
            } else {
                // 部分存在
                $this->warning('请备份数据表[' . $tableStr . ']数据，继续操作将会覆盖表数据！');
                $res = $this->confirm("确认继续执行？否 将跳过 {$this->desc} 流程");
                if (!$res) {
                    return self::RES_SKIP;
                }
            }
        }
        return self::RES_SUCCESS;
    }

    // 进行初始化
    private function initDb() {
        // 初始化执行
        $username = $this->getUsername();
        $password = $this->getPassword();
        [$passwordHash, $passwordSalt] = password_handle($password);
        $baseSql = parse_sql_file(
            ds_replace(YUNJ_VENDOR_SRC_PATH . 'init/sql/base.sql'),
            true,
            ['__PREFIX__', '__CHARSET__', '__ADMIN_MEMBER_USERNAME__', '__ADMIN_MEMBER_PASSWORD_SALT__', '__ADMIN_MEMBER_PASSWORD_HASH__'],
            [$this->getDbConnConfig('prefix'), $this->getDbCharset(), $username, $passwordSalt, $passwordHash],
        );
        Db::transaction(function () use ($baseSql) {
            foreach ($baseSql as $itemSql) {
                Db::execute($itemSql);
            }
        });
        // 同步系统路由和权限数据
        AuthService::syncSystemDatas();
        
        $this->isInit = true;
    }

    /**
     * @return bool
     */
    public function isInit(): bool {
        return $this->isInit;
    }

    // 获取username
    public function getUsername() {
        while (!$this->username) {
            $username = $this->ask('请输入管理员账户[字母/数字/_/-]（留空随机生成）');
            if (!$username) $username = rand_char(5);
            if (!preg_match("/^[A-Za-z0-9\_\-]+$/", $username)) {
                $this->warning('管理员账户名仅支持[字母/数字/_/-]组合');
                continue;
            }
            $this->username = $username;
            break;
        }
        return $this->username;
    }

    // 获取password
    public function getPassword() {
        while (!$this->password) {
            $password = $this->ask('请输入管理员密码[字母/数字/_/-]（留空随机生成）');
            if (!$password) $password = rand_char(8);
            if (!preg_match("/^[A-Za-z0-9\_\-]+$/", $password)) {
                $this->warning('管理员账户密码仅支持[字母/数字/_/-]组合');
                continue;
            }
            $this->password = $password;
            break;
        }
        return $this->password;
    }

}